﻿/**
 * Copyright (c) @CompanyNameMagicTag 2021-2023. All rights reserved.
 *
 * Description: Encapsulation of OS Hardware Interfaces
 */

#ifndef OAL_LINUX_HARDWARE_H
#define OAL_LINUX_HARDWARE_H

 /* 其他头文件包含 */
#include "../oal_util.h"
#include <wdm.h>
#include <gpio.h>
#include <ntddk.h>
#include <acpiioct.h>


/* 宏定义 */
typedef void (*oal_irq_handler_t)(void); \

#define IRQ_HANDLED 1

#define OAL_HI_TIMER_REG_BASE 0x10105000

#define OAL_HI_TIMER_NUM            2
#define OAL_HI_TIMER_ENABLE         1
#define OAL_HI_TIMER_DISABLE        0
#define OAL_HI_TIMER_INT_DISABLE    1
#define OAL_HI_TIMER_INT_CLEAR      0
#define OAL_HI_TIMER_DEFAULT_PERIOD 1

#define OAL_HI_TIMER_IRQ_NO 80 /* 5113 : 5   5115:80 */

#define OAL_HI_TIMER_FREE_MODE   0 /* 测试新增 */
#define OAL_HI_TIMER_CYCLE_MODE  1
#define OAL_HI_TIMER_SIZE_32_BIT 1
#define OAL_HI_TIMER_WRAPPING    0
#define OAL_HI_TIMER_INT_OCCUR   1
#define OAL_HI_TIMER_INT_VALID   0x01
#define OAL_HI_TIMER_NO_DIV_FREQ 0x0

#define OAL_HI_SC_REG_BASE 0x10100000
#define OAL_HI_SC_CTRL     (OAL_HI_SC_REG_BASE + 0x0000)

#define OAL_IRQ_ENABLE    1 /* 可以中断 */
#define OAL_IRQ_FORBIDDEN 0 /* 禁止中断 */

/* 数组最后一个成员用来保存save时间 */
/* 数组倒数第二个成员用来保存save的类型 */
#define OAL_TIMER_IRQ_TYPE_MAX_NUM    255
#define MAX_NUM_CORES    2
#define OAL_TIMER_IRQ_SAVE_TIME_INDEX (OAL_TIMER_IRQ_TYPE_MAX_NUM - 1)
#define OAL_TIMER_IRQ_SAVE_TYPE_INDEX (OAL_TIMER_IRQ_TYPE_MAX_NUM - 2)
typedef KIRQL oal_irqreturn_t;


/* 枚举定义 */
typedef enum {
    OAL_5115TIMER_ONE,
    OAL_5115TIMER_SEC,

    OAL_5115TIMER_BUTT
} oal_5115timer_enum;

/* STRUCT定义 */
typedef struct cpumask* oal_cpumask;

#define OAL_SA_SHIRQ IRQF_SHARED /* 中断类型 */

typedef uint32_t(*oal_irq_intr_func)(void*);
typedef int32_t(*oal_dbac_isr_func)(int);

typedef struct resource oal_resource;

typedef struct {
    volatile uint32_t timerx_load;
    volatile uint32_t timerx_value;
    volatile uint32_t timerx_control;
    volatile uint32_t timerx_intclr;
    volatile uint32_t timerx_ris;
    volatile uint32_t timerx_mis;
    volatile uint32_t timerx_bgload;
    volatile uint32_t reserve;
} oal_hi_timerx_reg_stru;
/* timer控制寄存器 */
typedef union {
    volatile uint32_t _value;
    struct {
        volatile uint32_t oneshot : 1;    /* 选择计数模式 0：回卷计数 1：一次性计数 */
        volatile uint32_t timersize : 1;  /* 16bit|32bit计数操作模式 0：16bit 1：32bit */
        volatile uint32_t timerpre : 2;   /* 预分频因子 00：不分频 01：4级分频 10：8级分频 11：未定义，设置相当于分频因子10 */
        volatile uint32_t reserved0 : 1;  /* 保留位 */
        volatile uint32_t intenable : 1;  /* 中断屏蔽位 0：屏蔽 1：不屏蔽 */
        volatile uint32_t timermode : 1;  /* 计数模式 0：自由模式 1：周期模式 */
        volatile uint32_t timeren : 1;    /* 定时器使能位 0：禁止 1：使能 */
        volatile uint32_t reserved1 : 24; /* 保留位 */
    } bits_stru;
} oal_hi_timer_control_union;

/* timer2_3寄存器 */
typedef struct {
    oal_hi_timerx_reg_stru ast_timer[OAL_5115TIMER_BUTT];
} oal_hi_timer_reg_stru;
typedef struct {
    oal_hi_timer_control_union u_timerx_config;
} oal_hi_timerx_config_stru;

/* PCI驱动相关定义 */
typedef struct pci_driver oal_pci_driver_stru;
typedef struct pci_device_id oal_pci_device_id_stru;
typedef struct pci_dev oal_pci_dev_stru;
typedef struct dev_pm_ops oal_dev_pm_ops_stru;
//typedef pm_message_t oal_pm_message_t;

/* 中断设备结构体 */
typedef struct {
    uint32_t irq;                 /* 中断号 */
    int32_t l_irq_type;              /* 中断类型标志 */
    void* p_drv_arg;               /* 中断处理函数参数 */
    char* pc_name;                 /* 中断设备名字 只为界面友好 */
    PKINTERRUPT p_irq_intr;   // 中断对象
    oal_irq_intr_func p_irq_intr_func; /* 中断处理函数地址 */
} oal_irq_dev_stru;

/* 全局变量声明 */
extern oal_hi_timer_reg_stru* g_reg_timer;
extern uint32_t g_irq_save_time[MAX_NUM_CORES][OAL_TIMER_IRQ_TYPE_MAX_NUM];

/* 函数声明 */
/*
 * 函 数 名  : oal_irq_free
 * 功能描述  : 释放中断处理程序
 * 输入参数  : st_osdev: 中断设备结构体
 */
OAL_STATIC OAL_INLINE void oal_irq_free(oal_irq_dev_stru* st_osdev)
{
    // 释放 IRQ
    if (st_osdev->irq != 0) {
        PKINTERRUPT irq_change = (PKINTERRUPT)st_osdev->irq;
        IoDisconnectInterrupt(irq_change);
    }

    // 释放 st_osdev 结构体内存（如果是动态分配的）
    ExFreePool(st_osdev);
}

/*
 * 函 数 名  : oal_irq_interrupt
 * 功能描述  : 中断服务程序
 * 输入参数  : l_irq: 中断号
 *             p_dev: 中断设备
 * 返 回 值  : IRQ_HANDLED中断程序处理完毕
 */
OAL_STATIC OAL_INLINE oal_irqreturn_t oal_irq_interrupt(int32_t l_irq, void* p_dev)
{
    oal_irq_dev_stru* st_osdev = (oal_irq_dev_stru*)p_dev;

    st_osdev->p_irq_intr_func((void*)st_osdev);

    return IRQ_HANDLED;
}

/*
 * 函 数 名  : oal_irq_setup
 * 功能描述  : 注册中断。
 * 输入参数  : st_osdev: 中断设备结构体
 */
OAL_STATIC OAL_INLINE int32_t oal_irq_setup(oal_irq_dev_stru* st_osdev)
{
    NTSTATUS status;

    if (st_osdev == NULL) {
        DbgPrint("oal_irq_setup: Invalid parameter");
        return STATUS_INVALID_PARAMETER;
    }

    if (st_osdev->p_irq_intr_func == NULL) {
        DbgPrint("oal_irq_setup: Interrupt handler function is NULL");
        return STATUS_INVALID_PARAMETER;
    }

    if (st_osdev->irq == 0) {
        DbgPrint("oal_irq_setup: Invalid IRQ number");
        return STATUS_INVALID_PARAMETER;
    }

    status = IoConnectInterrupt(
        &st_osdev->p_irq_intr,
        (PKSERVICE_ROUTINE)st_osdev->p_irq_intr_func,
        st_osdev->p_drv_arg,
        NULL,
        st_osdev->irq,
        0,
        0,
        LevelSensitive,
        FALSE,
        TRUE,
        FALSE
    );

    if (!NT_SUCCESS(status)) {
        DbgPrint("oal_irq_setup: IoConnectInterrupt failed with status 0x%lx for IRQ %d", status, st_osdev->irq);
        return status;
    }

    return STATUS_SUCCESS;
}

/*
 * 函 数 名  : oal_irq_trigger
 * 功能描述  : 软件启动目标核的硬件中断
 */
OAL_STATIC OAL_INLINE void oal_irq_trigger(uint8_t uc_cpuid)
{
}
#define GPIO_MIN 0
#define GPIO_MAX 99
BOOLEAN GPIO_IS_VALID(LONG gpioPin)
{
    if (gpioPin >= GPIO_MIN && gpioPin <= GPIO_MAX) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
static __inline LONG oal_gpio_is_valid(LONG i_number)
{
    return GPIO_IS_VALID(i_number);
}

//gpio 参数有问题

_Must_inspect_result_
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
FORCEINLINE
WdmIoTargetOpen(
    _In_ uint32_t ul_gpio,
    _In_ const char* pc_label
)
{
    NTSTATUS status;
    HANDLE FileHandle = NULL;
    IO_STATUS_BLOCK IoStatusBlock;
    OBJECT_ATTRIBUTES ObjectAttributes;

    // 1. 创建object attributes
    UNICODE_STRING DeviceName;
    RtlInitUnicodeString(&DeviceName, L"\\Device\\YourDeviceName"); // 替换为实际的设备名称

    InitializeObjectAttributes(&ObjectAttributes,
        &DeviceName,
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
        NULL,
        NULL);

    // 2. 打开gpio口
    status = IoCreateFile(&FileHandle,
        FILE_GENERIC_READ | FILE_GENERIC_WRITE,
        &ObjectAttributes,
        &IoStatusBlock,
        NULL,
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        FILE_OPEN,
        FILE_SYNCHRONOUS_IO_NONALERT,
        NULL,
        0,
        CreateFileTypeNone,
        NULL,
        IO_NO_PARAMETER_CHECKING);

    return status;
}

OAL_STATIC OAL_INLINE int32_t oal_gpio_request(uint32_t ul_gpio, const char* pc_label)
{
    return WdmIoTargetOpen(ul_gpio, pc_label);
}

_Must_inspect_result_
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
WdmIoTargetClose(
    _In_ HANDLE FileHandle
)
{
    NTSTATUS status;
    if (FileHandle != NULL) {
        status = ZwClose(FileHandle);
        if (!NT_SUCCESS(status)) {
            // 处理关闭失败的情况，例如记录日志
            return status;
        }
    }
    return STATUS_SUCCESS;
}

OAL_STATIC OAL_INLINE void oal_gpio_free(uint32_t ul_gpio)
{
    HANDLE FileHandle;
    WdmIoTargetClose(FileHandle);

}

NTSTATUS ConfigureGpioAsOutput(ULONG GpioPinNumber)
{
    PVOID gpioBaseAddress;
    PVOID gpioDirectionRegister;
    PVOID gpioDataRegister;

    // 获取GPIO控制器的基地址
    gpioBaseAddress = GetGpioControllerBaseAddress();
    //假设GPIO控制器的硬件手册中提供了以下偏移量：
    //    •	方向寄存器偏移量：0x04
    //    •	数据寄存器偏移量：0x08
    //    则可以在代码中定义这些宏：
    // 计算方向寄存器和数据寄存器的地址
    gpioDirectionRegister = gpioBaseAddress;
    //+ GPIO_DIRECTION_OFFSET;
    gpioDataRegister = gpioBaseAddress;
    //+ GPIO_DATA_OFFSET;

// 设置方向寄存器，将指定引脚配置为输出
    *(volatile ULONG*)gpioDirectionRegister |= (1 << GpioPinNumber);

    return STATUS_SUCCESS;
}

// 获取GPIO控制器的基地址
PVOID GetGpioControllerBaseAddress() {
    PDEVICE_OBJECT deviceObject = NULL;
    PCM_RESOURCE_LIST resourceList = NULL;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor = NULL;
    PHYSICAL_ADDRESS physicalAddress;
    PVOID baseAddress = NULL;
    ULONG requiredSize = 0;
    DEVICE_REGISTRY_PROPERTY DeviceProperty;
    // 获取设备资源列表
    if (NT_SUCCESS(IoGetDeviceProperty(deviceObject, DeviceProperty, 0, (PVOID*)&resourceList, &requiredSize))) {
        // 遍历资源列表，查找内存资源
        for (ULONG i = 0; i < resourceList->List[0].PartialResourceList.Count; i++) {
            resourceDescriptor = &resourceList->List[0].PartialResourceList.PartialDescriptors[i];
            if (resourceDescriptor->Type == CmResourceTypeMemory) {
                physicalAddress = resourceDescriptor->u.Memory.Start;
                // 映射物理地址到虚拟地址
                baseAddress = MmMapIoSpace(physicalAddress, resourceDescriptor->u.Memory.Length, MmNonCached);
                break;
            }
        }
    }

    // 释放设备对象引用
    ObDereferenceObject(deviceObject);


    return baseAddress;
}

OAL_STATIC OAL_INLINE int oal_gpio_direction_output(uint32_t ul_gpio, int l_level)
{

    return ConfigureGpioAsOutput(ul_gpio);

}

ULONG GetInterruptNumberFromGpioPin(uint32_t ul_gpio) {
    ULONG interruptNumber;

    // 获取中断号
    interruptNumber = 1;

    return  interruptNumber;
}



OAL_STATIC OAL_INLINE int32_t oal_gpio_to_irq(uint32_t ul_gpio)
{
    return GetInterruptNumberFromGpioPin(ul_gpio);
}

OAL_STATIC OAL_INLINE int32_t oal_request_irq(uint32_t ul_irq,
    PKSERVICE_ROUTINE p_handler,
    uint32_t ul_flags,
    const char* p_name,
    void* p_dev)
{
    PKINTERRUPT p_interrupt;
    PVOID irql;
    KAFFINITY affinity;
    BOOLEAN share_vector;

    // 初始化参数
    irql = (PVOID)ul_irq;
    affinity = 0; // 默认为所有处理器
    share_vector = FALSE; // 不共享中断向量

    // 注册中断处理程序
    NTSTATUS status = IoConnectInterrupt(
        &p_interrupt,          // 输出参数，指向中断对象
        p_handler,             // 中断处理程序
        irql,                  // 中断请求级别
        NULL,                  // 中断向量，NULL 表示使用 irql
        (ULONG)irql,                  // 中断同步级别
        affinity,              // 处理器亲和性
        share_vector,          // 是否共享中断向量
        LevelSensitive,                 // 是否延迟中断服务例程
        FALSE,
        TRUE,
        FALSE                 // 是否启用自动同步
    );
    if (!NT_SUCCESS(status)) {
        // 错误处理
        return status;
    }

    // 保存中断对象指针
    // 通常需要保存 p_interrupt 以便后续操作

    return status;
}




OAL_STATIC OAL_INLINE int32_t oal_gpio_get_value(uint32_t ul_gpio)
{
    return IOCTL_GPIO_READ_PINS;
}

OAL_STATIC OAL_INLINE void oal_gpio_set_value(uint32_t ul_gpio, int32_t value)
{
    IOCTL_GPIO_WRITE_PINS;
}

#define DELAY_TIME_MS 500
OAL_STATIC OAL_INLINE void oal_wifi_reg_on_pull_up(int32_t wifi_gpio_addr)
{
    if (!oal_gpio_is_valid(wifi_gpio_addr)) {
        oal_io_print("wifi_reg_on_pull_up:fail to get wifi gpio!\n");
        return;
    }
    /* 如果已经上过电，则直接返回 */
    if (oal_gpio_get_value(wifi_gpio_addr) == 1) {
        oal_io_print("wifi_reg_on_pull_up:WL_REG_ON has been pulled up in wifi_reg_on_pull_up!!!\n");
        return;
    }
    oal_mdelay(DELAY_TIME_MS);
    oal_gpio_direction_output(wifi_gpio_addr, 1);
    oal_mdelay(DELAY_TIME_MS);
}

OAL_STATIC OAL_INLINE void oal_wifi_reg_on_pull_down(int32_t wifi_gpio_addr)
{
    if (!oal_gpio_is_valid(wifi_gpio_addr)) {
        oal_io_print("wifi_reg_on_pull_down:fail to get wifi gpio!\n");
        return;
    }
    /* 如果已经下过电，则直接返回 */
    if (oal_gpio_get_value(wifi_gpio_addr) == 0) {
        oal_io_print("wifi_reg_on_pull_down:WL_REG_ON has been pulled down in wifi_reg_on_pull_down!!!\n");
        return;
    }

    oal_gpio_direction_output(wifi_gpio_addr, 0);
    oal_mdelay(DELAY_TIME_MS);
}

/*
 * 函 数 名  : oal_irq_set_affinity
 * 功能描述  : 将指定的中断号绑定到指定的cpu上执行
 * 输入参数  : irq: 中断号
 *             ul_cpu: cpu掩码
 */
OAL_STATIC OAL_INLINE int32_t oal_irq_set_affinity(uint32_t irq, uint32_t ul_cpu)
{
    KAFFINITY affinity_mask;
    int32_t l_ret;

    // 创建亲和性掩码
    affinity_mask = 1ULL << ul_cpu;

    // 设置中断的 CPU 亲和性
    KeSetSystemAffinityThread(affinity_mask);
    return OAL_SUCC;
}

/* 创建一个新的被使用资源区 */
#define oal_request_mem_region(start, n, name) request_mem_region(start, n, name)
#define oal_release_mem_region(start, n)       release_mem_region(start, n)

#define oal_ioremap(cookie, size)           ioremap(cookie, size)
#define oal_ioremap_nocache(_cookie, _size) ioremap_nocache(_cookie, _size)

#define oal_iounmap(cookie)                 iounmap(cookie)

//#define oal_writel(_ul_val, _ul_addr) writel(_ul_val, (void*)(uintptr_t)(_ul_addr))

//#define oal_readl(_ul_addr) readl((void *)(uintptr_t)(_ul_addr))
//#define oal_readl(_ul_addr) KeReadLong((PVOID)(_ul_addr))

#define oal_writew(_us_val, _ul_addr) writew(_us_val, _ul_addr)

#define oal_readw(_ul_addr) readw(_ul_addr)

NTSTATUS oal_writel(ULONG _ul_val, void* _ul_addr) {

    PHYSICAL_ADDRESS addr_phy = MmGetPhysicalAddress(_ul_addr);
    PVOID mappedAddress = MmMapIoSpace(addr_phy, sizeof(ULONG), MmNonCached);
    if (mappedAddress == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    WRITE_PORT_ULONG((PULONG)mappedAddress, _ul_val);

    MmUnmapIoSpace(mappedAddress, sizeof(ULONG));
    return STATUS_SUCCESS;
}

NTSTATUS oal_readl(void* _ul_addr) {

    PHYSICAL_ADDRESS addr_phy = MmGetPhysicalAddress(_ul_addr);
    PVOID mappedAddress = MmMapIoSpace(addr_phy, sizeof(ULONG), MmNonCached);
    if (mappedAddress == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    READ_PORT_ULONG((PULONG)mappedAddress);

    MmUnmapIoSpace(mappedAddress, sizeof(ULONG));
    return STATUS_SUCCESS;
}

/* 将var中[pos, pos + bits-1]比特清零,  pos从0开始编号 e.g oal_clearl_bits(var, 4, 2) 表示将Bit5~4清零 */
OAL_STATIC OAL_INLINE void oal_clearl_bits(void* addr, uint32_t pos, uint32_t bits)
{
    uint32_t value;

    if (oal_unlikely(addr == NULL)) {
        oal_warn_on(1);
        return;
    }
    value = oal_readl(addr);
    value &= ~((((uint32_t)1 << (bits)) - 1) << (pos));
    oal_writel(value, addr);
}

/* 将var中[pos, pos + bits-1]比特设置为val,  pos从0开始编号 e.g oal_setl_bits(var, 4, 2, 2) 表示将Bit5~4设置为b'10 */
OAL_STATIC OAL_INLINE void oal_setl_bits(void* addr, uint32_t pos, uint32_t bits, uint32_t val)
{
    uint32_t value;
    if (oal_unlikely(addr == NULL)) {
        oal_warn_on(1);
        return;
    }
    value = oal_readl(addr);
    value &= ~((((uint32_t)1 << (bits)) - 1) << (pos));
    value |= ((uint32_t)((val) & (((uint32_t)1 << (bits)) - 1)) << (pos));
    oal_writel(value, (addr));
}

OAL_STATIC OAL_INLINE void oal_clearl_bit(void* addr, uint32_t pos)
{
    uint32_t value;
    if (oal_unlikely(addr == NULL)) {
        oal_warn_on(1);
        return;
    }
    value = oal_readl(addr);
    value &= ~(1 << (pos));
    oal_writel(value, (addr));
}

OAL_STATIC OAL_INLINE void oal_setl_bit(void* addr, uint32_t pos)
{
    uint32_t value;
    if (oal_unlikely(addr == NULL)) {
        oal_warn_on(1);
        return;
    }
    value = oal_readl(addr);
    value |= (1 << pos);
    oal_writel(value, (addr));
}

OAL_STATIC OAL_INLINE void oal_clearl_mask(void* addr, uint32_t mask)
{
    uint32_t value;
    if (oal_unlikely(addr == NULL)) {
        oal_warn_on(1);
        return;
    }
    value = oal_readl(addr);
    value &= ~(mask);
    oal_writel(value, (addr));
}

OAL_STATIC OAL_INLINE void oal_setl_mask(void* addr, uint32_t mask)
{
    uint32_t value;
    if (oal_unlikely(addr == NULL)) {
        oal_warn_on(1);
        return;
    }
    value = oal_readl(addr);
    value |= (mask);
    oal_writel(value, (addr));
}

OAL_STATIC OAL_INLINE void oal_value_mask(void* addr, uint32_t value, uint32_t mask)
{
    uint32_t reg;
    if (oal_unlikely(addr == NULL)) {
        oal_warn_on(1);
        return;
    }
    reg = oal_readl(addr);
    reg &= ~(mask);
    value &= mask;
    reg |= value;
    oal_writel(reg, (addr));
}

#endif /* end of oal_hardware.h */